package cn.green.core.adapt.comps.table;

import cn.green.core.adapt.models.table.OrmTable;
import cn.green.core.common.QTableConstant;
import cn.green.core.components.database.session.dml.DeleteSession;
import cn.green.core.components.database.session.dml.InsertSession;
import cn.green.core.components.database.session.dml.UpdateSession;
import cn.green.core.components.entity.QCondition;
import cn.green.core.components.setter.DeleteKey;
import cn.green.core.components.setter.PrimaryKey;
import cn.green.core.components.table.TableTypeCom;
import cn.green.core.excel.QExcel;
import cn.green.core.excel.model.Column;
import cn.green.core.excel.model.impls.ParentColumn;
import cn.green.core.executor.DqlExecutor;
import cn.green.core.model.QFieldModel;
import cn.green.core.model.QTableModel;
import cn.green.core.quick.ThreadDataStore;
import cn.green.core.quick.cache.comp.Key;
import cn.green.core.scanner.anno.comps.QTableComponent;
import cn.green.core.scanner.store.OrmTableStore;
import cn.green.manage.service.QDqlService;
import cn.green.utils.OrmAppUtils;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

/**
 * @author wang.yishu
 * @version 1.0
 * @className OrmTableType
 * @description TODO
 * @date 2025/5/14 14:14
 */
@QTableComponent
public class OrmTableType implements TableTypeCom {
    private static QDqlService qDqlService;

    @Override
    public String dataTypeName() {
        return "OrmTableType";
    }

    @Override
    public String dataTypeCode() {
        return "ORM_TABLE_TYPE";
    }

    @Override
    public boolean needBuildConditionSql() {
        return true;
    }

    @Override
    public boolean canBeSelected() {
        return false;
    }

    @Override
    public String optionsPrefixUrl(
            QTableModel tableModel
    ) {
        return "";
    }

    @Override
    public String[] excludeConditionFields(
            QTableModel tableModel
    ) {
        return new String[0];
    }

    @Override
    public List<QFieldModel> fixFields(QTableModel tableModel) {
        if (tableModel instanceof OrmTable) {
            List<QFieldModel> fields = tableModel.getFields();
            if (fields == null) {
                fields = new ArrayList<>();
            }
            return fields;
        }
        return Collections.emptyList();
    }

    @Override
    public QFieldModel getPrimaryKeyField(QTableModel tableModel) {
        OrmTable ormTable = OrmTableStore.get(tableModel.getSourceName(), tableModel.getSchemeName(), tableModel.getTableName());
        if (ormTable == null) {
            throw new RuntimeException("there is no orm table '" + tableModel.getSourceName() + "." + tableModel.getSchemeName() + "." + tableModel.getTableName() + "'");
        }
        return ormTable.getPrimary();
    }

    @Override
    public PrimaryKey getPrimaryKey(QTableModel tableModel) {
        OrmTable ormTable = OrmTableStore.get(tableModel.getSourceName(), tableModel.getSchemeName(), tableModel.getTableName());
        if (ormTable == null) {
            throw new RuntimeException("there is no orm table '" + tableModel.getSourceName() + "." + tableModel.getSchemeName() + "." + tableModel.getTableName() + "'");
        }
        return ormTable.getPrimaryKey();
    }

    @Override
    public QFieldModel getDeleteKeyField(QTableModel tableModel) {
        OrmTable ormTable = OrmTableStore.get(tableModel.getSourceName(), tableModel.getSchemeName(), tableModel.getTableName());
        if (ormTable == null) {
            throw new RuntimeException("there is no orm table '" + tableModel.getSourceName() + "." + tableModel.getSchemeName() + "." + tableModel.getTableName() + "'");
        }
        return ormTable.getDeleted();
    }

    @Override
    public DeleteKey getDeleteKey(QTableModel tableModel) {
        OrmTable ormTable = OrmTableStore.get(tableModel.getSourceName(), tableModel.getSchemeName(), tableModel.getTableName());
        if (ormTable == null) {
            throw new RuntimeException("there is no orm table '" + tableModel.getSourceName() + "." + tableModel.getSchemeName() + "." + tableModel.getTableName() + "'");
        }
        return ormTable.getDeleteKey();
    }

    @Override
    public QFieldModel getParentKeyField(QTableModel tableModel) {
        OrmTable ormTable = OrmTableStore.get(tableModel.getSourceName(), tableModel.getSchemeName(), tableModel.getTableName());
        if (ormTable == null) {
            throw new RuntimeException("there is no orm table '" + tableModel.getSourceName() + "." + tableModel.getSchemeName() + "." + tableModel.getTableName() + "'");
        }
        return ormTable.getParent();
    }

    @Override
    public boolean canBuildConditionSql(QTableModel tableModel) {
        QFieldModel parentKeyField = this.getParentKeyField(tableModel);
        return parentKeyField == null;
    }

    protected boolean hasChildren(QTableModel tableModel, QFieldModel parentField, Object parentVal) {
        DqlExecutor bean = OrmAppUtils.getBean(DqlExecutor.class);
        JSONObject param = new JSONObject();
        param.put(parentField.getFieldName(), parentVal);
        JSONArray array = bean.originData(tableModel.getSourceName(), tableModel.getSchemeName(), tableModel.getTableName(), param, false);
        return array != null && array.size() > 0;
    }

    @Override
    public List<InsertSession> insertSessions(QTableModel tableModel, JSONObject record) {
        QFieldModel parentKeyField = this.getParentKeyField(tableModel);
        if (parentKeyField == null) {
            return Collections.emptyList();
        }
        JSONArray children = record.getJSONArray("children");
        if (children == null) {
            return Collections.emptyList();
        }
        List<InsertSession> sessions = new ArrayList<>();
        for (int i = 0; i < children.size(); i++) {
            JSONObject child = children.getJSONObject(i);
            InsertSession insertSession = new InsertSession();
            insertSession.setRecord(child);
            insertSession.setTable(tableModel);
            insertSession.setRecordSetter((Object primaryCurdResult, JSONObject primaryRecord, JSONObject r) -> {
                r.put(parentKeyField.getFieldName(), primaryCurdResult);
            });
            sessions.add(insertSession);
        }
        return sessions;
    }

    @Override
    public List<UpdateSession> updateSessions(QTableModel tableModel, JSONObject record, String... conditions) {
        return Collections.emptyList();
    }

    @Override
    public List<DeleteSession> deleteSessions(QTableModel tableModel, JSONObject record, String... conditions) {
        QFieldModel parentKeyField = this.getParentKeyField(tableModel);
        if (parentKeyField == null) {
            return Collections.emptyList();
        }
        QFieldModel primaryKeyField = this.getPrimaryKeyField(tableModel);
        if (parentKeyField == null) {
            return Collections.emptyList();
        }
        AtomicBoolean hasSession = new AtomicBoolean(true);
        List<DeleteSession> sessions = new ArrayList<>();

        Object parentVal = record.get(primaryKeyField.getFieldName());
        if (hasChildren(tableModel, parentKeyField, parentVal)) {
            DeleteSession deleteSession = new DeleteSession();
            deleteSession.setTable(tableModel);
            deleteSession.setRecord(new JSONObject());
            deleteSession.setRecordSetter((Object primaryCurdResult, JSONObject primaryRecord, JSONObject r) -> {
                r.put(parentKeyField.getFieldName(), parentVal);
            });
            sessions.add(deleteSession);
        }
        return sessions;
    }

    @Override
    public JSONArray selectOptions(String source, String scheme, String tableName) {
        return null;
    }

    @Override
    public JSONArray arrangeQueries(JSONArray data, QTableModel table, JSONObject param) {
        QFieldModel parentKeyField = this.getParentKeyField(table);
        QFieldModel primaryKeyField = this.getPrimaryKeyField(table);
        boolean isTree = false;
        if (parentKeyField != null) {
            isTree = true;
        }
        if (isTree) {
            JSONObject root = new JSONObject();
            root.put(primaryKeyField.getFieldName(), 0);
            this.buildTree(table, data, root, param, false);
            return root.getJSONArray("children");
        }
        return data;
    }

    public boolean buildTree(QTableModel table, JSONArray data, JSONObject parent, JSONObject param, boolean parentHit) {
        String parentPrimaryKey = this.getPrimaryKeyField(table).getFieldName();
        String parentKey = this.getParentKeyField(table).getFieldName();
        //得到父级id
        Object parentId = parent.get(parentPrimaryKey);
        //父级是否命中
        boolean hit = QCondition.Compare.compare(table, parent, param);
        boolean childHit = false;
        boolean currentHit = false;
        if (data != null && !data.isEmpty()) {
            List<Object> children = data.stream().filter(item -> parentId.equals(((JSONObject) item).get(parentKey))).collect(Collectors.toList());
            if (!children.isEmpty()) {
                List<JSONObject> childrenTarget = null;
                for (Object child : children) {
                    JSONObject childJsonObject = (JSONObject) child;
                    childHit = this.buildTree(table, data, childJsonObject, param, hit);
                    if (!currentHit && childHit) {
                        currentHit = true;
                    }
                    if (childHit || hit || parentHit) {
                        if (childrenTarget == null) {
                            childrenTarget = new ArrayList<>();
                        }
                        childrenTarget.add(childJsonObject);
                    }
                }
                parent.put("children", childrenTarget);
            }
        }
        return hit || childHit || currentHit || parentHit;
    }

    @Override
    public JSONObject arrangeDetail(JSONObject detail, QTableModel table) {
        return detail;
    }

    @Override
    public List<Column> tableExcelColumns(QTableModel table) {
        QFieldModel parentKeyField = this.getParentKeyField(table);
        if (parentKeyField == null) {
            return Collections.emptyList();
        }
        ParentColumn parentColumn = new ParentColumn(1, parentKeyField, "(如果父级为导入数据，请输入导入数据的行号如[行号])");
        JSONArray list = ThreadDataStore.get(new Key("Columns:Tree:" + table.getSourceName() + ":" + table.getSchemeName() + ":" + table.getTableName()),
                JSONArray.class, new JSONArray(), () -> {
                    if (qDqlService == null) {
                        qDqlService = OrmAppUtils.getBean(QDqlService.class);
                    }
                    return qDqlService.list(table.getSourceName(), table.getSchemeName(), table.getTableName(), new JSONObject());
                });
        JSONArray options = new JSONArray();
        JSONObject root = new JSONObject();
        root.put("label", "根节点");
        root.put("value", 0);
        options.add(root);
        if (list != null) {
            for (int i = 0; i < list.size(); i++) {
                JSONObject item = list.getJSONObject(i);
                JSONObject option = new JSONObject();
                option.put("value",item.getString(this.getPrimaryKeyField(table).getFieldName()));
                option.put("label",item.getString("name"));
                options.add(option);
            }
        }
        parentColumn.setOptions(options);
        return Collections.singletonList(parentColumn);
    }

    @Override
    public void parseExcelRowRecord(QTableModel table, JSONObject record, List<QExcel.RowRecord> rowRecords) {
        QFieldModel primaryKeyField = this.getPrimaryKeyField(table);
        QFieldModel parentKeyField = this.getParentKeyField(table);
        Object parentKey = record.get(parentKeyField.getFieldName());
        if (parentKey == null || "".equals(parentKey)) {
            parentKey = parentKeyField.getDefaultValue();
        } else {
            if (parentKey instanceof String && !((String) parentKey).isEmpty() && ((String) parentKey).startsWith("[")
                    && ((String) parentKey).endsWith("]")) {
                try {
                    String parentKeyString = parentKey.toString();
                    String rowIndexStr = parentKeyString.substring(1, parentKeyString.length() - 1);
                    int parentIndex = Integer.parseInt(rowIndexStr);
                    QExcel.RowRecord rowRecord = rowRecords.stream().filter(item -> item.getRowNumber() == parentIndex).findFirst().orElse(null);
                    if (rowRecord != null) {
                        parentKey = rowRecord.getRecord().get(QTableConstant.DQL.PRIMARY_TABLE + "." + primaryKeyField.getFieldName());
                    }
                } catch (NumberFormatException e) {
                    parentKey = parentKeyField.getDefaultValue();
                }
            }
        }
        record.put(parentKeyField.getFieldName(), parentKey);
    }
}
